package com.spudtech.collision
{
    
    import flash.geom.*;
    
    import com.spudtech.*;
    import com.spudtech.error.*;
    
    
    public class SpudGrid extends SpudCollider
    {
        
        protected var _tileData : Array;
        
        protected var _gridWidth : uint;
        protected var _gridHeight : uint;
        
        protected var _tileWidth : uint;
        protected var _tileHeight : uint;
        
        public function SpudGrid(position : Point,
                                 grid_size : Point,
                                 tile_size : Point,
                                 tile_data : *)
        {
            super(position);
            
            _gridWidth = grid_size.x;
            _gridHeight = grid_size.y;
            
            _tileWidth = tile_size.x;
            _tileHeight = tile_size.y;
            
            _tileData = new Array();
            
            
            if (tile_data is Array)
            {
                // We accept either a two-dimensional
                // grid or a one-dimensional list
                
                if (tile_data.length == 0)
                {
                    throw new SpudEmptyDataError("Empty tile data array given");
                }
                else if (tile_data[0] is Array)
                {
                    // We assume it is a two-dimensional Array
                    
                    var y : int;
                    var x : int;
                    
                    for (y = 0 ; y < gridHeight ; y++)
                    {
                        if (y > tile_data.length)
                        {
                            // We're past the length
                            // of the tile data
                            break;
                            
                        }
                        
                        if (!(tile_data[y] is Array))
                        {
                            // It turns out that it is
                            // *not* two-dimensional
                            
                            throw new TypeError("Tile data Array looked two-dimensional, but a non-Array 'row' was found");
                            
                        }
                        
                        tileData.push(new Array());
                        
                        for (x = 0 ; x < gridWidth ; x++)
                        {
                            if (x >= tile_data[y].length)
                            {
                                // We're past the length
                                // of the row data
                                break;
                                
                            }
                            
                            if (tile_data[y][x] is int)
                            {
                                // It is an int
                                
                                if (tile_data[y][x] >= 0)
                                {
                                    // It is non-negative
                                    // We can add it
                                    
                                    tileData[y].push(tile_data[y][x]);
                                    
                                }
                                else
                                {
                                    // We can only have non-negative
                                    // tile index values
                                    throw new RangeError("Negative tile index in initial data");
                                }
                                
                            }
                            else if (tile_data[y][x] is Boolean)
                            {
                                // You want to use Boolean values?
                                // Fine.
                                // true evaluates to an index of 1
                                // false evaluates to an index of 0
                                
                                if (tile_data[y][x])
                                {
                                    // It is true
                                    tileData[y].push(1);
                                }
                                else
                                {
                                    // It if false
                                    tileData[y].push(0);
                                }
                                
                            }
                            else
                            {
                                throw new TypeError("Invalid type of tile index given (Tile index values must be given as int or Boolean)");
                            }
                            
                        }
                        
                    }
                    
                }
                else
                {
                    // It is a one-dimensional Array
                    
                    y;
                    x;
                    
                    var tile_index : int;
                    
                    for (y = 0 ; y < gridHeight ; y++)
                    {
                        
                        _tileData.push(new Array());
                        
                        for (x = 0 ; x < gridWidth ; x++)
                        {
                            // The tile index is 'y'
                            // rows down and 'x'
                            // columns over
                            tile_index = (y * gridWidth) + x;
                            
                            if (tile_index > tile_data.length)
                            {
                                // We're past the end of the data
                                
                                // Remove the last row because
                                // it is incomplete
                                _tileData[y].pop();
                                
                                // This really should be reported...
                                
                                break;
                                
                            }
                            
                            if (tile_data[tile_index] is int)
                            {
                                // It's an int
                                
                                if (tile_data[tile_index] >= 0)
                                {
                                    // It is non-negative
                                    // We can add it
                                    
                                    _tileData[y].push(tile_data[tile_index]);
                                    
                                }
                                else
                                {
                                    // We can only use non-negative
                                    // tile index values
                                    
                                    throw new RangeError("Invalid tile index given (Tile index values may not be negative)");
                                    
                                }
                                
                            }
                            else if (tile_data[tile_index] is Boolean)
                            {
                                // Just like for a two-dimensional
                                // data Array,
                                // true evaluates to 1
                                // false evaluates to 0
                                
                                if (tile_data[tile_index])
                                {
                                    // It is true
                                    
                                    _tileData[y].push(1);
                                    
                                }
                                else
                                {
                                    // It is false
                                    
                                    _tileData[y].push(0);
                                    
                                }
                                
                            }
                            else
                            {
                                throw new TypeError("Invalid type of tile index given (Tile index values must be given as int or Boolean)");
                            }
                            
                        }
                        
                    }
                    
                }
                
            }
            else if (tile_data is String)
            {
                if (tile_data.indexOf("\n"))
                {
                    // It is flat data
                    
                    var tile_values : Array = tile_data.split(",");
                    
                    x;
                    y;
                    
                    tile_index;
                    var tile_val : int;
                    
                    for (y = 0 ; y < gridHeight ; y++)
                    {
                        _tileData.push(new Array());
                        
                        for (x = 0 ; x < gridWidth ; x++)
                        {
                            // 'y' rows down, 'x'
                            // columns over
                            tile_index = (y * gridHeight) + x;
                            
                            if (tile_index >= tile_values.length)
                            {
                                // We're past the end of the
                                // grid data
                                
                                // Remove the last row because
                                // it is incomplete
                                _tileData[y].pop();
                                
                                break;
                            }
                            
                            
                            tile_val = parseInt(tile_values[tile_index].match(/-?\d+/));
                            
                            if (tile_val >= 0)
                            {
                                // It is non-negative
                                // We can use it
                                
                                _tileData[y].push(tile_val);
                                
                            }
                            else
                            {
                                // We can only use non-negative
                                // tile index values
                                
                                throw new RangeError("Invalid tile value given (Tile index values may not be negative");
                                
                            }
                            
                        }
                        
                    }
                    
                }
                
            }
            else
            {
                throw new TypeError("Invalid tile grid data given (Tile data must either be an Array or a CSV String");
            }
            
        }
        
        
        public function get gridWidth() : uint
        {
            return _gridWidth;
        }
        public function set gridWidth(val : uint) : void
        {
            _gridWidth = val;
        }
        public function get gridHeight() : uint
        {
            return _gridHeight;
        }
        public function set gridHeight(val : uint) : void
        {
            _gridHeight = val;
        }
        
        public function get tileWidth() : uint
        {
            return _tileWidth;
        }
        public function set tileWidth(val : uint) : void
        {
            _tileWidth = val;
        }
        public function get tileHeight() : uint
        {
            return _tileHeight;
        }
        public function set tileHeight(val : uint) : void
        {
            _tileHeight = val;
        }
        
        public function get tileData() : Array
        {
            return _tileData;
        }
        // No setter, too hairy
        
        
        public function getRectsInArea(area : SpudRect) : Array
        {
            var rects : Array = new Array();
            
            var area_left : int = int(Math.floor(area.left / tileWidth));
            var area_top : int = int(Math.floor(area.top / tileHeight));
            
            var area_right : int = int(Math.floor(area.right / tileWidth));
            var area_bottom : int = int(Math.floor(area.bottom / tileHeight));
            
            
            for (var x : int = area_left ; x < area_right ; x++)
            {
                if (x < 0)
                {
                    continue;
                }
                if (x > gridWidth)
                {
                    break;
                }
                
                for (var y : int = area_top ; y < area_bottom ; y++)
                {
                    if (y < 0)
                    {
                        continue;
                    }
                    if (y > gridHeight)
                    {
                        break;
                    }
                    
                    if (tileData[y][x] != 0)
                    {
                        rects.push(
                            new SpudRect(new Point(x,y), new Point(tileWidth,tileHeight))
                        );
                    }
                    
                }
                
                
            }
            
            return rects;
            
        }
        
    }
    
}
